print('程序开始运行...')

print('正在加载库time...')  # 用于输出文件时的时间戳
from time import strftime, localtime, sleep, perf_counter

print('正在加载库openai...')  # DEEPSEEK-API连接的主要软件包,请自行下载`pip3 install openai`
from openai import *

print('正在加载库requests...')  # 查询余额使用的包
from requests import request

print('正在加载库itertools...')  # 等待deepseek回答时转圈用的生成器
from itertools import cycle

print('正在加载库threading...')  # 等待deepseek回答时转圈用的多线程模块
from threading import Thread, Event

print('正在加载库json...')  # 导入导出messages
import json

print('正在加载库os...')  # 加载deepseek-api-key环境变量使用
import os

print('正在定义代码...')

done: Event
spinner: Thread
start_time:float
first_elapsed:float

def spin(done: Event):
    """等待deepseek响应时用此线程输出转圈动画"""
    global start_time,first_elapsed
    for char in cycle(r'\|/-'):  # 无限输出4个符号的循环
        first_elapsed=round(perf_counter() - start_time, 2)
        print(f'\r{char}正在生成回答中,请稍后...(已持续{first_elapsed}秒)', end='')
        if done.wait(.1):  # 主线程发出done.set()信号，退出转圈
            break
    print('\r', end='')  # 清理残余的字符


def get_response(msg, msg_md, beta, completion_type, kwargs):
    """调动各个handle_xxx_response函数,处理api发出的错误"""
    global done, spinner
    if completion_type != 'fim':  # FIM不支持messages,也不用加到对话上下文中
        messages.append({"role": "user", "content": msg})
        kwargs['messages'].append({"role": "user", "content": msg})
    if completion_type == 'prefix':  # 加入对话前缀,但因deepseek会生成回答,所以不需要添加到全局的messages,而是只加入当前的messages(kwargs['messages'])
        kwargs['messages'].append({'role': 'assistant', 'content': prefix, 'prefix': True})
    try:  # 根据对话类型使用不同函数,并处理错误
        if completion_type == 'fim':
            handle_fim_response(kwargs)
        elif kwargs['model'] == 'deepseek-chat':
            handle_chat_response(msg_md, beta, completion_type, kwargs)
        elif kwargs['model'] == 'deepseek-reasoner':
            handle_reasoner_response(model, messages, msg, msg_md)
    except BadRequestError as e:
        print(f'\033[31mError-400:请求体格式错误=>{e}\033[0m')
    except AuthenticationError as e:
        print(f'\033[31mError-401:API key 错误,认证失败=>{e}\033[0m')
    except UnprocessableEntityError as e:
        print(f'\033[31mError-422:请求体参数错误=>{e}\033[0m')
    except RateLimitError as e:
        print(f'\033[31mError-429:请求速率(TPM 或 RPM)达到上限=>{e}\033[0m')
    except APIStatusError as e:  # 有些deepseek的错误码在openai库中没有对应的错误类,所以需要手动判断错误码
        if e.status_code == 402:
            print(f'\033[31mError-402:账号余额不足=>{e}\033[0m')
        elif e.status_code == 500:
            print(f'\033[31mError-500:服务器内部故障=>{e}\033[0m')
        elif e.status_code == 503:
            print(f'\033[31mError-503:服务器负载过高=>{e}\033[0m')
        else:  # 应该遇不到
            print(f'\033[31m发出请求时发生未知错误:{e}\033[0m')
    finally:
        done.set()
        spinner.join()


def handle_chat_response(msg_md, beta, completion_type, kwargs):
    """处理deepseek-chat的回答"""
    global done, spinner,start_time
    start_time=perf_counter()
    done = Event()  # 旋转指针停止的判断事件
    spinner = Thread(target=spin, args=(done,))  # 创建旋转指针线程
    spinner.start()  # 启动线程
    
    if beta:  # beta_client的baseurl是https://api.deepseek.com/beta,而client是https://api.deepseek.com
        response = beta_client.chat.completions.create(**kwargs, stream=True)  # 发送请求，stream=True为流式输出
    else:
        response = client.chat.completions.create(**kwargs, stream=True)
    
    collected_chunks = []  # 每一块流数据的内容都存储在这里
    is_done = False  # deepseek生成第一块内容(非空内容)后次线程停止,此为判断的信号
    
    for chunk in response:  # 此处的response是生成器
        content_now = chunk.choices[0].delta.content  # 获取当前数据块的内容
        if content_now is not None:
            if not is_done:  # 停止次线程
                done.set()
                spinner.join()
                is_done = True
            print(content_now, end="", flush=True)  # 流式将内容输出到屏幕上,flush=True是确保实时显示
            collected_chunks.append(content_now)
    
    last_elapsed=round(perf_counter()-start_time,2)
    # Token Usage: 386(completion:377, prompt: 9(cached:0))
    token = f'Token Usage:{chunk.usage.total_tokens}(completion:{chunk.usage.completion_tokens},prompt:{chunk.usage.prompt_tokens}(cached:{chunk.usage.prompt_tokens_details.cached_tokens}))(总用时:{last_elapsed}s,首token用时:{first_elapsed}s)'
    print(f"\n\033[37m{token}\033[0m\n")
    content = "".join(collected_chunks)  # 拼接内容
    
    if completion_type != 'prefix':  # 如果是对话前缀续写模式就把前缀和输出内容拼接到一起再加入messages
        messages.append({'role': 'assistant', 'content': content})
    else:
        messages.append({'role': 'assistant', 'content': str(prefix) + content})
    
    log = {
        'time': str(strftime("%Y-%m-%d %H:%M:%S", localtime())),
        'completion_type': completion_type if completion_type else None,
        'model': model,
        'messages': messages,
        'usage': {
            'total': int(chunk.usage.total_tokens),
            'completion': int(chunk.usage.completion_tokens),
            'prompt': {
                'prompt': int(chunk.usage.prompt_tokens),
                'cached': int(chunk.usage.prompt_tokens_details.cached_tokens)
                }
            }
        }
    if completion_type == '':  # 针对不同的对话类型使用不同的保存文件函数
        save_chat_md(msg_md, content, token, log)
    elif completion_type == 'prefix':
        save_prefix_md(msg_md, content, token, log)
    elif completion_type == 'json-output':
        save_json_md(msg_md, content, token, log)


def handle_fim_response(kwargs):
    """处理FIM补全模式下的回答"""
    global done, spinner,start_time
    start_time=perf_counter()
    done = Event()  # 旋转指针停止的判断事件
    spinner = Thread(target=spin, args=(done,))  # 创建旋转指针线程
    spinner.start()  # 启动线程
    
    response = beta_client.completions.create(**kwargs, stream=True)  # FIM补全需要使用beta_client,stream=True为流式输出
    collected_chunks = []  # 每一块流数据的内容都存储在这里
    is_done = False  # deepseek生成第一块内容(非空内容)后次线程停止,此为判断的信号
    
    for chunk in response:  # 此处的response是生成器
        content_now = chunk.choices[0].text
        if content_now is not None:
            if not is_done:  # 停止次线程
                done.set()
                spinner.join()
                is_done = True
            print(content_now, end="", flush=True)  # 流式将内容输出到屏幕上,flush=True是确保实时显示
            collected_chunks.append(content_now)
    
    last_elapsed = round(perf_counter() - start_time, 2)
    # Token Usage: 386(completion:377, prompt: 9(cached:0))
    token = f'Token Usage:{chunk.usage.total_tokens}(completion:{chunk.usage.completion_tokens},prompt:{chunk.usage.prompt_tokens}(cached:{chunk.usage.prompt_tokens_details.cached_tokens}))(总用时:{last_elapsed}s,首token用时:{first_elapsed}s)'
    print(f"\n\033[37m{token}\033[0m\n")
    content = "".join(collected_chunks)  # 拼接内容
    
    log = {
        'time': str(strftime("%Y-%m-%d %H:%M:%S", localtime())),
        'completion_type': 'fim',
        'model': kwargs['model'],
        'prompt': kwargs['prompt'],
        'content': content,
        'suffix': kwargs['suffix'],
        'usage': {
            'total': int(chunk.usage.total_tokens),
            'completion': int(chunk.usage.completion_tokens),
            'prompt': int(chunk.usage.prompt_tokens)
            }
        }
    try:  # 写入md文件
        with open("log\\" + get_legal_filename(str(strftime("%Y-%m-%d-%H-%M-%S", localtime())) + ' FIM ') + '.md', 'w+',
                  encoding='utf-8') as file:
            file.write('# FIM补全\n\n')
            file.write('### ' + kwargs['prompt'] + '\n\n')
            file.write(content.replace('\n', '\n\n') + '\n\n')
            file.write('### ' + kwargs['suffix'] + '\n\n')
            file.write(f'*{token}*')
    except Exception as e:
        print(f'\033[31m写入markdown文件时出错:{e}\033[0m')
    try:  # 写入log文件
        with open(r'log\log.log', 'a', encoding='utf-8') as log_file:
            log_file.write(json.dumps(log, ensure_ascii=False) + '\n')
    except Exception as e:
        print(f'\033[31m写入log文件时出错:{e}\033[0m')


def handle_reasoner_response(model, messages, msg, msg_md):
    """处理deepseek-reasoner的回答"""
    global done, spinner,start_time
    start_time=perf_counter()
    done = Event()  # 旋转指针停止的判断事件
    spinner = Thread(target=spin, args=(done,))  # 创建旋转指针线程
    spinner.start()  # 启动线程
    
    response = client.chat.completions.create(model=model, messages=messages, stream=True)
    collected_chunks = []  # deepseek输出的内容存储在这里
    collected_reasoning_chunks = []  # deepseek输出的思维链存储于这里
    reasoning_now = 0  # 确认deepseek输出的状态,0为deepseek未开始输出或者开头为了保持tcp连接而输出空内容,1是在输出思维链,2是在输出内容
    is_done = False  # deepseek生成第一块内容(非空内容)后次线程停止,此为判断的信号
    for chunk in response:  # 此处的response是生成器
        if reasoning_now < 2:
            reasoning_content_now = chunk.choices[0].delta.reasoning_content
            if reasoning_content_now is not None:
                if not is_done:  # 停止次线程
                    done.set()
                    spinner.join()
                    is_done = True
                    print("\033[32m", end='', flush=True)  # 思维链的内容是绿色的
                reasoning_now = 1
                print(reasoning_content_now, end='', flush=True)  # 实时输出思维链内容
                collected_reasoning_chunks.append(reasoning_content_now)
            else:
                if reasoning_now == 1:  # 若判断为True则思维链已经输出完毕
                    reasoning_now = 2
                    print("\033[0m\n\n", end='', flush=True)  # 输出内容不需要像思维链一样的绿色字体,所以将输出格式恢复正常
                    content_now = chunk.choices[0].delta.content  # 由于这个块包含了第一个输出内容,为了保证内容完整性,所以在这里处理这个内容
                    print(content_now, end="", flush=True)
                    collected_chunks.append(content_now)
        else:  # 处理正常输出的内容
            content_now = chunk.choices[0].delta.content
            if content_now is not None:
                print(content_now, end="", flush=True)
                collected_chunks.append(content_now)
    
    last_elapsed = round(perf_counter() - start_time, 2)
    # Token Usage: 853(completion:770(reasoning: 232), prompt: 83(cached:0))
    token = f'Token Usage:{chunk.usage.total_tokens}(completion:{chunk.usage.completion_tokens}(reasoning:{chunk.usage.completion_tokens_details.reasoning_tokens}),prompt:{chunk.usage.prompt_tokens}(cached:{chunk.usage.prompt_tokens_details.cached_tokens}))(总用时:{last_elapsed}s,首token用时:{first_elapsed}s)'
    print(f"\n\033[37m{token}\033[0m\n")
    reasoning_content = ''.join(collected_reasoning_chunks)  # 拼接思维链内容
    content = "".join(collected_chunks)  # 拼接输出内容
    messages.append({'role': 'assistant', 'content': content})
    log = {
        'time': str(strftime("%Y-%m-%d %H:%M:%S", localtime())),
        'model': model,
        'messages': messages,
        'reasoning_content': str(reasoning_content),
        'usage': {
            'total': int(chunk.usage.total_tokens),
            'completion': {
                'completion': int(chunk.usage.completion_tokens),
                'reasoning': chunk.usage.completion_tokens_details.reasoning_tokens
                },
            'prompt': {
                'prompt': int(chunk.usage.prompt_tokens),
                'cached': int(chunk.usage.prompt_tokens_details.cached_tokens)
                }
            }
        }
    try:  # 写入md文件
        with open("log\\" + get_legal_filename(str(strftime("%Y-%m-%d-%H-%M-%S", localtime())) + msg) + '.md', 'w+',
                  encoding='utf-8') as file:
            reasoning_content_md = get_reasoner_md(reasoning_content)
            file.write(f'{msg_md}\n\n')  # 写入用户问题
            file.write(str(reasoning_content_md) + '\n\n\n\n')  # 写入思维链
            file.write(str(content) + '\n\n')  # 写入输出内容
            file.write(f'*{token}*')
    except Exception as e:
        print(f'\033[31m写入markdown文件时出错:{e}\033[0m')
    try:  # 写入log文件
        with open(r'log\log.log', 'a', encoding='utf-8') as log_file:
            log_file.write(json.dumps(log, ensure_ascii=False) + '\n')
    except Exception as e:
        print(f'\033[31m写入log文件时出错:{e}\033[0m')


def get_legal_filename(filename: str) -> str:
    illegal_char = r'\,/,:,*,?,",<,>,|'.split(',')
    for char in illegal_char:
        filename = filename.replace(char, '')
    if len(filename) > 55:
        filename = filename[:51]
    return filename


def save_chat_md(msg_md, content, token, log):
    """将deepseek-chat的输出内容保存的文件里"""
    try:
        with open("log\\" + get_legal_filename(str(strftime("%Y-%m-%d-%H-%M-%S", localtime())) + msg) + '.md', 'w+',
                  encoding='utf-8') as file:
            file.write(f'{msg_md}\n\n')
            file.write(str(content) + '\n\n')
            file.write(f'*{token}*')
    except Exception as e:
        print(f'\033[31m写入markdown文件时出错:{e}\033[0m')
    try:
        with open(r'log\log.log', 'a', encoding='utf-8') as log_file:
            log_file.write(json.dumps(log, ensure_ascii=False) + '\n')
    except Exception as e:
        print(f'\033[31m写入log文件时出错:{e}\033[0m')


def save_json_md(msg_md, content, token, log):
    """将json输出模式下的输出内容保存的文件里"""
    try:
        with open(
                "log\\" + get_legal_filename(str(strftime("%Y-%m-%d-%H-%M-%S", localtime())) + ' json ' + msg) + '.md',
                'w+',
                encoding='utf-8') as file:
            file.write('### System:' + messages[0]['content'].replace('\n', '\n\n### ') + '\n\n')
            file.write(f'{msg_md}\n\n')
            file.write(str(content) + '\n\n')
            file.write(f'*{token}*')
    except Exception as e:
        print(f'\033[31m写入markdown文件时出错:{e}\033[0m')
    try:
        with open(r'log\log.log', 'a', encoding='utf-8') as log_file:
            log_file.write(json.dumps(log, ensure_ascii=False) + '\n')
    except Exception as e:
        print(f'\033[31m写入log文件时出错:{e}\033[0m')


def save_prefix_md(msg_md, content, token, log):
    """将对话前缀续写模式下的输出内容存储到文件里"""
    try:
        with open("log\\" + get_legal_filename(
                str(strftime("%Y-%m-%d-%H-%M-%S", localtime())) + ' prefix ' + msg) + '.md', 'w+',
                  encoding='utf-8') as file:
            file.write(f'# 对话前缀续写\n\n')
            file.write(f'{msg_md}\n\n')
            file.write(f'### {prefix}\n\n')
            file.write(str(content) + '\n\n')
            file.write(f'*{token}*')
    except Exception as e:
        print(f'\033[31m写入markdown文件时出错:{e}\033[0m')
    try:
        with open(r'log\log.log', 'a', encoding='utf-8') as log_file:
            log_file.write(json.dumps(log, ensure_ascii=False) + '\n')
    except Exception as e:
        print(f'\033[31m写入log文件时出错:{e}\033[0m')


def get_input(text='请输入内容,新行end结束:') -> str:
    """获取多行输入"""
    print(text, end='')
    full_input = ''
    while True:
        text_now = input()
        if text_now != 'end':
            full_input += text_now + '\n'
        else:
            break
    try:
        full_input = full_input[:-1]
        return full_input
    except:
        return ''


def get_msg_md(text: str) -> str: return '\n\n'.join(['# ' + line for line in text.split('\n')])


def get_reasoner_md(text: str) -> str: return '\n> \n'.join(
        ['> ' + line for line in text.replace('\n\n', '\n').split('\n')])


def get_messages_md(messages: list[dict]) -> str: return ''.join([get_msg_md(message['content']) + '\n' if (
        message['role'] == 'user' or message['role'] == 'system') else message['content'] + '\n\n' for message in
                                                                  messages])


def check_settings(settings_got: str, settings_required: str) -> bool:
    """当advanced=True时判断输入的内容需要执行哪个代码块"""
    all_settings = [str(y) for y in range(1, 10)] + ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
    settings_not_required = [str(x) for x in all_settings if x not in settings_required]
    return all([(setting_got in settings_required) for setting_got in settings_got]) and all(
            [(setting_got not in settings_not_required) for setting_got in settings_got])


print('读取api_key中...')
api_key = os.environ.get('DEEPSEEK_API_KEY')  # 读取环境变量DEEPSEEK_API_KEY中的数据
if not api_key:  # 若该环境变量不存在则api_key的值为None
    print(f'\033[31m读取api_key失败:环境变量DEEPSEEK_API_KEY不存在！\033[0m')
    sleep(3)
    raise SystemExit

print('正在创建与deepseek的连接...')
client = OpenAI(api_key=api_key, base_url="https://api.deepseek.com")

print('正在查询余额中')
try:
    balance_response = request("GET", "https://api.deepseek.com/user/balance",
                               headers={'Accept': 'application/json', 'Authorization': 'Bearer ' + api_key}, data={})
    balance_response_list = json.loads(balance_response.text)
    if float(balance_response_list['balance_infos'][0]['total_balance']) >= 0.1:
        print(f'\033[32m余额:¥{balance_response_list['balance_infos'][0]['total_balance']}\033[0m')
    else:
        print(f'\033[31m余额不足:¥{balance_response_list['balance_infos'][0]['total_balance']}\033[0m')
except Exception as e:
    print(f'\033[31m查询余额时发生错误:{e}\033[0m')

print(f'\033[32m程序初始化完成！！！\033[0m\n\n{'=' * 40}\n')

model_choice = input(
        '1.deepseek普通模型(deepseek-chat)\n2.deepseek推理模型(deepseek-reasoner)\n3.稍后再选择(支持高级功能)\n请选择:')  # 选择模型,若在此处选择后面就不可更改,且不能操作messages和system
advanced = False
if model_choice == '1':
    model = 'deepseek-chat'
elif model_choice == '2':
    model = 'deepseek-reasoner'
elif model_choice == '3':
    advanced = True  # 支持高级功能
else:
    raise ValueError('请输入1、2、3！')

print('')

messages = []
msg = ''
stop = []
max_tokens = 4096  # 初始值,其值可能会在后面改变
temperature = 1  # 初始值,其值可能会在后面改变
while True:
    kwargs = {}  # 用于传给client.chat.completions()
    beta = False  # 每次循环初始化,如果需要使用beta_client就为True
    completion_type = ''  # 若为普通对话则其值为空,可能的值('fim','prefix','json-output')
    if advanced:
        settings = input(
                '1.deepseek-chat   2.deepseek-reasoner   3.多行输入   4.FIM补全(beta)   5.对话前缀续写(beta)   6.JSON输出\n7.设置max_tokens(默认4096)   8.设置temperature(0-2)   9.打印当前设置\na.保存messages   b.读取messages   c.清空messages(不包括system)   d.设置/替换"system"   e.清空"system"\nf.messages转md   g.设置stop   h.清空stop   i.查询余额   j.退出\n可选:1,2,13,23,4,5,35,6,36,7,8,9,a,b,c,d,e,ce,f,g,h,i\n请选择(可多选):').lower()  # 使用lower()这样就不分大小写都可使用,更人性化
        if settings == '':
            print()
            continue
        elif check_settings(settings, '1'):
            msg = input('输入(deepseek-chat):')
            model = 'deepseek-chat'
        elif check_settings(settings, '2'):
            msg = input('输入(deepseek-reasoner):')
            model = 'deepseek-reasoner'
        elif check_settings(settings, '13'):
            msg = get_input('请输入内容,新行end结束(deepseek-chat):')
            model = 'deepseek-chat'
        elif check_settings(settings, '23'):
            msg = get_input('请输入内容,新行end结束(deepseek-reasoner):')
            model = 'deepseek-reasoner'
        elif check_settings(settings, '4'):
            if not 'beta_client' in locals().keys():
                beta_client = OpenAI(api_key=api_key, base_url="https://api.deepseek.com/beta")
            prompt = input('请输入开头内容(prompt):')
            if prompt == '':
                print()
                continue
            suffix = input('请输入结尾内容(suffix):')
            if suffix == '':
                print()
                continue
            kwargs['prompt'] = prompt
            kwargs['suffix'] = suffix
            model = 'deepseek-chat'
            beta = True
            completion_type = 'fim'
        elif check_settings(settings, '5'):
            if not 'beta_client' in locals().keys():
                beta_client = OpenAI(api_key=api_key, base_url="https://api.deepseek.com/beta")
            msg = input('输入(对话前缀续写):')
            if msg == '':
                print()
                continue
            prefix = input('请输入对话前缀:')
            if prefix == '':
                print()
                continue
            model = 'deepseek-chat'
            completion_type = 'prefix'
            beta = True
        elif check_settings(settings, '35'):
            if not 'beta_client' in locals().keys():
                beta_client = OpenAI(api_key=api_key, base_url="https://api.deepseek.com/beta")
            msg = get_input('输入(对话前缀续写),新行end结束:')
            if msg == '':
                print()
                continue
            prefix = get_input('请输入对话前缀,新行end结束:')
            if prefix == '':
                print()
                continue
            model = 'deepseek-chat'
            completion_type = 'prefix'
            beta = True
        elif check_settings(settings, '6'):
            if len(messages) <= 0 or messages[0]['role'] != 'system' or 'json' not in messages[0]['content'].lower():
                print('\033[31mJSON输出必须有system且system中必须有json字样!\033[0m\n')
                continue
            msg = input('输入(json-output):')
            model = 'deepseek-chat'
            completion_type = 'json-output'
            kwargs['response_format'] = {'type': 'json_object'}
        elif check_settings(settings, '36'):
            if len(messages) <= 0 or messages[0]['role'] != 'system' or 'json' not in messages[0]['content'].lower():
                print('\033[31mJSON输出必须有system且system中必须有json字样!\033[0m\n')
                continue
            msg = get_input('输入(json-output),新行end结束:')
            model = 'deepseek-chat'
            completion_type = 'json-output'
            kwargs['response_format'] = {'type': 'json_object'}
        elif check_settings(settings, '7'):
            try:
                tokens = input('请输入新的max_tokens(最大4096):')
                if int(tokens) < 1 or int(tokens) > 4096:
                    print('\033[31m请输入介于1-4096的数字!\033[0m\n')
                    continue
                max_tokens = int(tokens)
            except ValueError:  # 此错误可能会在上面第2行发生
                if tokens == '':
                    print('\033[31m请勿输入空数字!\033[0m\n')
                else:
                    print('\033[31m请勿输入非数字!\033[0m\n')
            else:
                print('\033[32m设置成功！\033[0m\n')
            continue
        elif check_settings(settings, '8'):
            try:
                new_temperature = input('请输入新的temperature(0-2):')
                if float(new_temperature) < 0 or float(new_temperature) > 2:
                    print('\033[31m请输入介于0-2的数字!\033[0m\n')
                    continue
                temperature = float(new_temperature)
            except ValueError:  # 此错误可能会在上面第2行发生
                if new_temperature == '':
                    print('\033[31m请勿输入空数字!\033[0m\n')
                else:
                    print('\033[31m请勿输入非数字!\033[0m\n')
            else:
                print('\033[32m设置成功！\033[0m\n')
            continue
        elif check_settings(settings, '9'):
            print(f'\033[32m当前messages\033[0m:{messages!r}')
            print(f'\033[32m当前max_tokens\033[0m:{max_tokens}')
            print(f'\033[32m当前temperature\033[0m:{temperature}')
            print(f'\033[32m当前stop\033[0m:{stop!r}\n')
            continue
        elif check_settings(settings, 'a'):  # 存储于saves\messages
            if len(messages) > 0:
                file_name = str(strftime("%Y-%m-%d-%H-%M-%S", localtime())) + 'messages.json'
                try:
                    with open('saves\\messages\\' + file_name, 'w+', encoding='utf-8') as file:
                        file.write(json.dumps(messages, ensure_ascii=False))
                except Exception as e:
                    print(f'\033[31m存储时出现错误:{e}\033[0m\n')
                else:
                    print(f'\033[32m成功存储到文件:saves\\messages\\{file_name}\033[0m\n')
            else:
                print(f'\033[31m不能将空消息列表存储到json文件中！\033[0m\n')
            continue
        elif check_settings(settings, 'b'):  # 加载于saves\messages
            file_name = input('将从saves\\messages中读取message文件,现有messages将被替换,请输入文件名:')
            try:
                with open('saves\\messages\\' + file_name, 'r', encoding='utf-8') as file:
                    messages_read = json.load(file)
                    if len(messages_read) > 0:
                        messages = messages_read
            except Exception as e:
                print(f'\033[31m读取时出现错误:{e}\033[0m\n')
            else:
                print(f'\033[32m成功读取messages文件\033[0m\n')
            continue
        elif check_settings(settings, 'c'):  # 不清空system(如有)
            if messages[0]['role'] != 'system':
                del messages[:]
            else:
                del messages[1:]
            print('\033[32m清空成功！\033[0m\n')
            continue
        elif check_settings(settings, 'd'):
            new_system = get_input('请输入内容,空取消,新行end结束:')
            if new_system == '':
                print()
                continue
            else:
                try:
                    if len(messages):
                        if messages[0]['role'] == 'system':
                            messages[0]['content'] = new_system
                        else:
                            messages.insert(0, {'role': 'system', 'content': new_system})
                    else:
                        messages.append({'role': 'system', 'content': new_system})
                except Exception as e:
                    print(f'\033[31添加时遇到了错误:{e}\033[0m\n')
                else:
                    print('\033[32m设置成功！\033[0m\n')
            continue
        elif check_settings(settings, 'e'):
            if len(messages):
                if messages[0]['role'] == 'system':
                    del messages[0]
                    print('\033[32m清空成功！\033[0m\n')
                else:
                    print('本来就没有system!\n')
            else:
                print('messages为空！\n')
            continue
        elif check_settings(settings, 'ce'):
            del messages[:]
            print('\033[32m清空成功!\033[0m\n')
            continue
        elif check_settings(settings, 'f'):
            if len(messages) > 0:
                file_name = str(strftime("%Y-%m-%d-%H-%M-%S", localtime())) + 'messages_to_md.md'
                try:
                    with open('saves\\md\\' + file_name, 'w+', encoding='utf-8') as file:
                        file.write(get_messages_md(messages))
                except Exception as e:
                    print(f'\033[31m存储时出现错误:{e}\033[0m\n')
                else:
                    print(f'\033[32m成功存储到文件:saves\\md\\{file_name}\033[0m\n')
            else:
                print(f'\033[31m不能将空消息列表存储到md文件中！\033[0m\n')
            continue
        elif check_settings(settings, 'g'):
            new_stop_str = input('请输入新的stop(json格式):').replace("'", '"')
            try:
                new_stop = json.loads(new_stop_str)
                if len(new_stop) > 16:
                    print('\033[31m请注意：stop最多有16项！\033[0m\n')
                else:
                    stop = new_stop
            except json.decoder.JSONDecodeError as e:
                print('\033[31m请以json格式输入!\033[0m\n')
            else:
                print('\033[32m设置成功！\033[0m\n')
            continue
        elif check_settings(settings, 'h'):
            stop = []
            print('\033[32m清空成功！\033[0m\n')
            continue
        elif check_settings(settings, 'i'):
            try:
                balance_response = request("GET", "https://api.deepseek.com/user/balance",
                                           headers={'Accept': 'application/json', 'Authorization': 'Bearer ' + api_key},
                                           data={})
                balance_response_list = json.loads(balance_response.text)
                if float(balance_response_list['balance_infos'][0]['total_balance']) >= 0.1:
                    print(f'\033[32m余额:¥{balance_response_list['balance_infos'][0]['total_balance']}\033[0m')
                else:
                    print(f'\033[31m余额不足:¥{balance_response_list['balance_infos'][0]['total_balance']}\033[0m')
            except Exception as e:
                print(f'\033[31m查询余额时发生错误:{e}\033[0m')
        elif check_settings(settings, 'j'):
            print('\n再见！')
            sleep(3)
            raise SystemExit
        else:
            print(f'\033[31m无效输入！\033[0m\n')
            continue
    else:
        msg = input('输入:')
    if msg == '' and completion_type != 'fim':
        print()
        continue
    msg_md = get_msg_md(msg)
    kwargs['model'] = model
    if completion_type != 'fim':
        kwargs['messages'] = messages.copy()
    if stop:
        kwargs['stop'] = stop
    kwargs['max_tokens'] = max_tokens
    if model != 'deepseek-reasoner':
        kwargs['temperature'] = temperature
    get_response(msg, msg_md, beta, completion_type, kwargs)
